package com.diao.elasticsearch;

import org.apache.http.HttpHost;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.core.CountRequest;
import org.elasticsearch.client.core.CountResponse;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.tasks.TaskAwareRequest;

import java.io.IOException;
import java.util.*;

/**
 * @author: Chenzhidiao
 * @date: 2020/4/27 10:11
 * @description:
 * @version: 1.0
 */
public class MyEsUtils {


    private static RestHighLevelClient client = null;

    /**
     * 获取客户端
     *
     * @return
     */
    public static RestHighLevelClient getRestHighLevelClient() {
        if (client == null) {
            try {
                client = MyEsClientPool.getClient();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return client;
    }

    /**
     * 关闭客户端
     */
    public static void closeClient(){
        if (client!=null){
            MyEsClientPool.returnClient(client);
        }
    }



    /**
     * 构建查询对象
     * @param filedsMap 查询条件 (key:查询字段 ,vlues:值)
     * @return
     */
    public static BoolQueryBuilder getQueryBuilder(Map<String,String> filedsMap){

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        Set<String> strings = filedsMap.keySet();
        for (String string : strings) {
            boolQueryBuilder.must(QueryBuilders.wildcardQuery(string,"*"+filedsMap.get(string)+"*"));
        }
        return boolQueryBuilder;
    }

    /**
     * 获取分页后的结果集
     * @param queryBuilder 查询对象
     * @param esIndex      索引名
     * @param pageNo    页数
     * @param pagesize  页大小
     * @return
     */
    public static List<String> getPageResultList(QueryBuilder queryBuilder, String esIndex,int pageNo,int pagesize){
        SearchRequest searchRequest = new SearchRequest(esIndex);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        if (pageNo>=1) {
            searchSourceBuilder.query(queryBuilder).from((pageNo - 1) * pagesize).size(pagesize);
        }else {
            searchSourceBuilder.query(queryBuilder).from(0).size(pagesize);
        }
        searchRequest.source(searchSourceBuilder);
        client = getRestHighLevelClient();
        SearchResponse searchResponse = null;

        try {
             searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 从response中获得结果
        List<String> list = new LinkedList<String>();
        searchResponse.getHits();

        SearchHits hits = searchResponse.getHits();

        Iterator<SearchHit> iterator = hits.iterator();
        while (iterator.hasNext()) {
            SearchHit next = iterator.next();
            list.add(next.getSourceAsString());
        }
        return list;
    }

    /**
     * 获取结果总数
     * @param queryBuilder
     * @param esIndex
     * @return
     */
    public static Long getResultCount(QueryBuilder queryBuilder, String esIndex){
        CountRequest countRequest=new CountRequest(esIndex);
        countRequest.query(queryBuilder);
        try {
            CountResponse response=getRestHighLevelClient().count(countRequest,RequestOptions.DEFAULT);
            long length = response.getCount();
            return length;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return 0L;


    }

    /**
     * 获取文档总数
     * @param index
     * @return
     */
    public static long getDocCount(String index){
        CountRequest countRequest = new CountRequest();
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.matchAllQuery());
        countRequest.source(searchSourceBuilder);
        CountResponse countResponse = null;
        client=getRestHighLevelClient();
        try {
            countResponse = client
                    .count(countRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return countResponse.getCount();
    }

    /**
     * 判断索引是否存在
     * @param esIndex
     * @return
     */
    public static boolean isIndexExist(String esIndex){
        boolean isExists = true;
        GetIndexRequest request = new GetIndexRequest(esIndex);
        try {
             isExists = getRestHighLevelClient().indices().exists(request, RequestOptions.DEFAULT);
             if (isExists){
                 System.out.println(String.format("索引%s已存在",esIndex));

             }else{
                 System.out.println(String.format("索引%s不存在",esIndex));
             }

        } catch (IOException e) {
            e.printStackTrace();
        }
        return isExists;
    }

    /**
     * 新建索引
     * @param esIndex
     * @param shards 分片数
     * @param replications 副本数
     * @param fileds 字段名->类型
     */
    public static void createIndex(String esIndex,int shards,int replications,Map<String,String> fileds){
        if (!isIndexExist(esIndex)){
            try {
                XContentBuilder builder = XContentFactory.jsonBuilder()
                        .startObject()
                        .field("properties")
                        .startObject();
                for (String s : fileds.keySet()) {
                    builder.field(s).startObject().field("index","true").field("type",fileds.get(s)).endObject();
                }
                builder.endObject().endObject();
                CreateIndexRequest request = new CreateIndexRequest(esIndex);
                request.settings(Settings.builder()
                        .put("index.number_of_shards", shards)
                        .put("index.number_of_replicas", replications)
                ).mapping(builder);
                CreateIndexResponse createIndexResponse = getRestHighLevelClient().indices().create(request, RequestOptions.DEFAULT);
                boolean acknowledged = createIndexResponse.isAcknowledged();
                if (acknowledged){
                    System.out.println(String.format("索引%s创建成功",esIndex));
                }else{
                    System.out.println(String.format("索引%s创建失败",esIndex));
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }else{
            System.out.println(String.format("索引%s已存在",esIndex));
        }
    }

    /**
     * 删除索引
     * @param esIndex
     */
    public static void deleteIndex(String esIndex){
        DeleteIndexRequest request = new DeleteIndexRequest(esIndex);

        try {
            AcknowledgedResponse deleteIndexResponse = getRestHighLevelClient().indices().delete(request, RequestOptions.DEFAULT);
            boolean acknowledged = deleteIndexResponse.isAcknowledged();
            if (acknowledged){
                System.out.println(String.format("索引%s已删除",esIndex));
            }else{
                System.out.println(String.format("索引%s删除失败",esIndex));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据id获取数据，返回map(字段名,字段值)
     * @param esIndex
     * @param id
     * @return
     */
    public static Map<String,Object> getDataById(String esIndex,String id){
        GetRequest request = new GetRequest(esIndex, id);
        GetResponse response = null;
        Map<String,Object> source = null;
        try {
            response = getRestHighLevelClient().get(request,RequestOptions.DEFAULT);
            if (response.isExists()){
                 source = response.getSource();

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return source;


    }

    /**
     * 更新文档
     * @param esIndex
     * @param id
     * @param updateFileds 更新的字段名->字段值
     */
    public static void updateDataById(String esIndex,String id,Map<String,Object> updateFileds){
        UpdateRequest request = new UpdateRequest(esIndex, id).doc(updateFileds);
        try {
            UpdateResponse response = getRestHighLevelClient().update(request, RequestOptions.DEFAULT);
            if (response.status()== RestStatus.OK){
                System.out.println(String.format("更新索引为%s,id为%s的文档成功",response.getIndex(),response.getId()));
            }else{
                System.out.println(String.format("更新索引为%s,id为%s的文档失败",response.getIndex(),response.getId()));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 删除指定id的文档
     * @param esIndex
     * @param id
     */
    public static void deleteDataById(String esIndex,String id){
        DeleteRequest request = new DeleteRequest(esIndex,id);
        try {
            DeleteResponse response = getRestHighLevelClient().delete(request, RequestOptions.DEFAULT);
            if (response.getResult()== DocWriteResponse.Result.DELETED){
                System.out.println(String.format("id为%s的文档删除成功",id));
            }else{
                System.out.println(String.format("id为%s的文档删除失败",id));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 批量插入
     * @param esIndex
     * @param datalist  数据集，数据格式为map<字段名,字段值>
     */
    public static void bulkLoad(String esIndex,List<Map<String,Object>> datalist){
        BulkRequest bulkRequest = new BulkRequest();
        for (Map<String,Object> data : datalist) {
            Object id = data.get("id");
            //如果数据包含id字段，使用数据id作为文档id
            if (id!=null){
                data.remove("id");
                bulkRequest.add(new IndexRequest(esIndex).id(id.toString()).source(data));
            }else{//让es自动生成id
                bulkRequest.add(new IndexRequest(esIndex).source(data));
            }
        }
        try {
            BulkResponse response = getRestHighLevelClient().bulk(bulkRequest, RequestOptions.DEFAULT);
            System.out.println(response.hasFailures());
            if (!response.hasFailures()){
                System.out.println(String.format("索引%s批量插入成功，共插入%d条",esIndex,datalist.size()));
            }else{
                System.out.println(String.format("索引%s批量插入失败",esIndex));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static void main(String[] args) {
        Map<String ,String> filedsMap = new HashMap<String,String>();
        filedsMap.put("area","Botswana");
        filedsMap.put("item","Roots, Other");
        BoolQueryBuilder queryBuilder = getQueryBuilder(filedsMap);
        List<String> list = getPageResultList(queryBuilder, "nv_excel_pickup_origi",1,5);
        System.out.println(list.size());
        for (String s : list) {
            System.out.println(s);
        }
        System.out.println("count:"+getResultCount(queryBuilder,"nv_excel_pickup_origi"));
       /* HashMap<String, String> fileds = new HashMap<String, String>();
        fileds.put("name","keyword");
        fileds.put("age","long");
        fileds.put("create_time","keyword");

        createIndex("company3",1,0,fileds);*/
        //deleteIndex("company3");
       /* HashMap<String, Object> fileds = new HashMap<String, Object>();
        fileds.put("age",25);
        fileds.put("name","wangwu2");
        fileds.put("@version",3);*/


        //deleteDataById("company","4");
      /*  ArrayList<Map<String, Object>> datas = new ArrayList<Map<String, Object>>();
        HashMap<String, Object> data1 = new HashMap<String, Object>();
        data1.put("id",5);
        data1.put("name","zhangsan");
        data1.put("age",18);
        HashMap<String, Object> data2 = new HashMap<String, Object>();
        data2.put("id",7);
        data2.put("name","diao");
        data2.put("age",22);
        datas.add(data1);
        datas.add(data2);
        bulkLoad("company",datas);*/
        closeClient();
    }

}
